<?php

namespace service\proxy;

use artisan\db;

/**
 * 记录代理使用情况
 * @example logger::log([]); 参数必须为键值对或者按照default_fields顺寻的序列
 */
class logger
{
    /**
     * pointer container
     * @var array
     */
    protected static $points = [];

    /**
     * log stored db
     * @var string
     */
    protected static $db_name = 'express';

    /**
     * log table
     * @var string
     */
    protected static $log_table = 'proxy_query_log';

    /**
     * db instance
     * @var null
     */
    protected static $db = null;

    /**
     * error logs
     * @var array
     */
    protected static $_error = [];

    /**
     * common info for log
     * @var array
     */
    public static $infos = [];

    /**
     * db $fields
     *
     * @var array
     */
    protected static $default_fields = [
        'express_no',
        'query_from',
        'query_source',
        'query_type',
        // 'proxy_ip',
        'proxy_try',
        'querier_ip',
        'express_company',
        'query_status',
        'error_info',
        'query_time',
        'query_cost',
    ];

    // CREATE TABLE IF NOT EXISTS `query_log` (
    //   `log_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
    //   `express_no` varchar(50) NOT NULL COMMENT '单号',
    //   `query_from` varchar(20) NOT NULL DEFAULT '' COMMENT '查询来源',
    //   `query_source` varchar(30) NOT NULL DEFAULT '' COMMENT '数据源',
    //   `query_type` varchar(20) NOT NULL DEFAULT '' COMMENT '查询类型,vpn,代理,原有形式',
    //   `proxy_ip` varchar(15) NOT NULL DEFAULT '' COMMENT '代理ip',
    //   `querier_ip` varchar(15) NOT NULL DEFAULT '0' COMMENT '查询者ip',
    //   `express_company` varchar(20) NOT NULL DEFAULT '' COMMENT '查询品牌',
    //   `query_status` varchar(10) NOT NULL COMMENT '查询结果是否成功',
    //   `error_info` varchar(255) NOT NULL DEFAULT '' COMMENT '错误信息',
    //   `query_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '时间',
    //   `query_cost` decimal(10,2) unsigned NOT NULL DEFAULT '0.00' COMMENT '查询耗时',
    //   PRIMARY KEY (`log_id`)
    // ) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4;
    // SET FOREIGN_KEY_CHECKS=1;

    /**
     * log
     *
     * @param  array $infos
     * @return integer
     */
    public static function log(array $infos = [])
    {
        if (is_int(key($infos)) && count(self::$default_fields) === count($infos)) {
            $infos = array_combine(self::$default_fields, $infos);
        }
        if ($_data = self::logInfoCheck(array_merge(self::$infos, $infos))) {
            return self::getDB()->insert($_data);
        }
    }

    /**
     * getLastQuery
     *
     * @return string|null
     */
    public static function getLastQuery()
    {
        return self::getDB()->getLastQuery();
    }

    /**
     * getError
     *
     * @todo artisan\db 增加对应方法
     * @return string|null
     */
    // public static function getError()
    // {
    //     return self::getDB()->getLastError();
    // }

    /**
     * log Info Check
     *
     * @param  array  $data
     * @return array
     */
    protected static function logInfoCheck(array $data)
    {
        is_array($data) or $data = (array) $data;
        $data = array_intersect_key($data, array_flip(self::$default_fields));
        return array_filter($data, function ($val) {
            return !is_null($val);
        });
    }

    /**
     * get a db instance
     *
     * @return \artisan\db;
     */
    private static function getDB($table = '')
    {
        if (self::$db === null) {
            self::$db = db::connect(self::$db_name);
        }
        return self::$db->table($table ?: self::$log_table);
    }

    /**
     * set a time point
     *
     * @param string $key
     * @return float
     */
    public static function setPoint($key = null)
    {
        $key or $key = date('Y_m_d_H_i_s') . rand(10000, 9999);
        return self::$points[$key] = microtime(true);
    }

    /**
     * getAllPoints
     *
     * @return array
     */
    public static function getAllPoints()
    {
        return self::$points;
    }

    /**
     * get two point diff
     *
     * @param  string $key_a
     * @param  string $key_b
     * @return float
     */
    public static function getPointDiff($key_a, $key_b)
    {
        if (isset(self::$points[$key_a]) && isset(self::$points[$key_b])) {
            return abs((float) self::$points[$key_a] - (float) self::$points[$key_b]);
        }
        return false;
    }

    /**
     * set a start point
     *
     *  @param string $key
     * @return float
     */
    public static function setStart($key = null)
    {
        return self::setPoint(self::getRandKey(is_string($key) ? $key : '_default_point') . '__START_POINT__');
    }

    /**
     * set a end point
     * @param string $key
     * @return float
     */
    public static function setEnd($key = null)
    {
        return self::setPoint(self::getRandKey(is_string($key) ? $key : '_default_point') . '__END_POINT__');
    }

    /**
     * startEndDiff
     * @param string $key
     * @return float
     */
    public static function startEndDiff($key = null)
    {
        return self::getPointDiff(self::getRandKey(is_string($key) ? $key : '_default_point') . '__START_POINT__', self::getRandKey(is_string($key) ? $key : '_default_point') . '__END_POINT__');
    }

    /**
     * get a random string
     *
     * @param  string $key
     * @return string
     */
    private static function getRandKey($key = null)
    {
        static $keys = [];
        if (!is_string($key)) {
            return uniqid('analysis_k', true);
        } elseif (!isset($keys[$key])) {
            $keys[$key] = uniqid('analysis_k', true);
        }
        return $keys[$key];
    }
}
